package com.spzx.payment.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.web.controller.BaseController;
import com.spzx.common.core.web.domain.AjaxResult;
import com.spzx.common.rabbit.constant.MqConst;
import com.spzx.common.rabbit.service.RabbitService;
import com.spzx.common.security.annotation.RequiresLogin;
import com.spzx.order.api.RemoteOrderInfoService;
import com.spzx.order.api.domain.OrderInfo;
import com.spzx.payment.config.AlipayConfig;
import com.spzx.payment.service.IAlipayService;
import com.spzx.payment.service.IPaymentInfoService;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.Map;

@Slf4j
@Controller
@RequestMapping("/alipay")
public class AlipayController extends BaseController {

    @Autowired
    private IAlipayService alipayService;

    @Autowired
    private RemoteOrderInfoService remoteOrderInfoService;

    @Autowired
    private IPaymentInfoService paymentInfoService;

    @Autowired
    private RabbitService rabbitService;

    @Operation(summary = "支付宝下单")
    @RequiresLogin
    @RequestMapping("/submitAlipay/{orderNo}")
    @ResponseBody
    public AjaxResult submitAlipay(@PathVariable(value = "orderNo") String orderNo) {
        String form = alipayService.submitAlipay(orderNo);
        return success(form);
    }

    @PostMapping("/callback/notify")
    @ResponseBody
    public String alipayNotify(@RequestParam Map<String, String> paramMap, HttpServletRequest request) throws AlipayApiException {
        log.info("AlipayController...alipayNotify方法执行了...");
        String failureResult = "failure";

        //验签（身份认证和防篡改）-需要一个公钥
        boolean flag = AlipaySignature.rsaCheckV1(paramMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
        if (!flag){
            log.error("验签失败");
            return failureResult;
        }
        //商家订单号
        String outTradeNo = paramMap.get("out_trade_no");
        //a. 商家需要验证该通知数据中的 out_trade_no 是否为商家系统中创建的订单号。
        R<OrderInfo> OrderInfoResult = remoteOrderInfoService.getByOrderNo(outTradeNo, SecurityConstants.INNER);
        if(R.FAIL == OrderInfoResult.getCode()){
            log.error("订单号被篡改");
            return failureResult;
        }

        //获取订单数据
        OrderInfo orderInfo = OrderInfoResult.getData();
        //b. 判断 total_amount 是否确实为该订单的实际金额（即商户订单创建时的金额）。
        String totalAmount = paramMap.get("total_amount");
        if (orderInfo.getTotalAmount().compareTo(new BigDecimal(totalAmount)) != 0) {
            log.error("订单金额被篡改");
            return failureResult;
        }
        //c. 校验通知中的 seller_id（或者 seller_email) 是否为 out_trade_no 这笔单据的对应的操作方（有的时候，一个商家可能有多个 seller_id/seller_email）。
        String sellerId = paramMap.get("seller_id");
        if (!"2088721050609972".equals(sellerId)) {
            log.error("商家身份被篡改");
            return failureResult;
        }
        //d. 验证 app_id 是否为该商家本身。
        String appId = paramMap.get("app_id");
        if (!AlipayConfig.app_id.equals(appId)){
            log.error("app_id被篡改");
            return failureResult;
        }

        //TRADE_SUCCESS 或 TRADE_FINISHED
        String tradeStatus = paramMap.get("trade_status");
        if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {
            //幂等处理
            // 正常的支付成功，我们应该更新交易记录状态
            //2：支付宝
            paymentInfoService.updatePaymentStatus(paramMap, 2);
            //基于MQ通知订单系统，修改订单状态
            rabbitService.sendMessage(MqConst.EXCHANGE_PAYMENT_PAY, MqConst.ROUTING_PAYMENT_PAY, outTradeNo);
            //基于MQ通知商品系统，扣减库存
            rabbitService.sendMessage(MqConst.EXCHANGE_PRODUCT, MqConst.ROUTING_MINUS, outTradeNo);

            return "success";
        }
        return failureResult ;
    }
}